package com.rankeiot.dev.util;

import cn.hutool.core.date.DateUtil;
//import org.noear.snack.core.utils.DateUtil;
import com.rankeiot.core.util.JSONUtil;
import org.springframework.util.StreamUtils;

import javax.crypto.Cipher;
import java.io.*;
import java.security.*;
import java.security.spec.PKCS8EncodedKeySpec;
import java.util.*;

@SuppressWarnings("AlibabaConstantFieldShouldBeUpperCase")
public class RsaUtil {
    private static final String algorithm="RSA";
    private static final int maxSize=1024;

    public static void main(String[] args) {
        //System.out.println(encrypt("hahaha"));
       // genLicense("Trail","6FD19B6EA58A81AC88C1290082CA7764",new Date());
        byte[] data=genLicense("Trail","6FD19B6EA58A81AC88C1290082CA7764","2022-12-31 12:00");
        File file=new File("license.dat");
        try(OutputStream out=new FileOutputStream(file)){
            out.write(data);
            out.flush();
            System.out.println("文件已生成到："+file.getAbsolutePath());
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    public static byte[] genLicense(String user,String SN,String date){
//        try {
            Date dt=  DateUtil.parse(date);
            return genLicense(user,SN,dt);
//        } catch (ParseException e) {
//            e.printStackTrace();
//        }
//        return null;
    }
    /**
     * license
     * 授权名称
     * 产品代码
     * 授权用户
     * mac
     * 到期时间(时间戳)
     * @param SN
     */
    public static byte[] genLicense(String user,String SN, Date date){
        //code mac

        Map<String,String> map=new HashMap<>();
        map.put("user",user);
        map.put("sn",SN);
        map.put("date",date.getTime()+"");
        return encrypt(JSONUtil.toJSONString(map));
    }
    public static byte[] encrypt(String input){
        try {
            return encrypt(input,loadPrivateKey());
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }
    /**
     * 从字符串中加载私钥
     *
     * @return : 私钥
     * @throws Exception
     */
    private static PrivateKey loadPrivateKey() throws Exception {
        try(InputStream in= RsaUtil.class.getResourceAsStream("/private.key")){
           byte[] data= StreamUtils.copyToByteArray(in);//Utils.transferToBytes(in);
            // 获取密钥工厂
            KeyFactory keyFactory = KeyFactory.getInstance(algorithm);
            // 构建密钥规范
            PKCS8EncodedKeySpec keyspec = new PKCS8EncodedKeySpec(data);
            // 生成私钥
            return keyFactory.generatePrivate(keyspec);
        }
    }

    /**
     * 使用密钥加密数据
     *
     * @param input          : 原文
     * @param key            : 密钥
     * @return : 密文
     * @throws Exception
     */
    private static byte[] encrypt(String input, Key key) throws Exception {
        int maxEncryptSize=input.length();
        // 获取Cipher对象
        Cipher cipher = Cipher.getInstance(algorithm);
        // 初始化模式(加密)和密钥
        cipher.init(Cipher.ENCRYPT_MODE, key);
        // 将原文转为byte数组
        byte[] data = input.getBytes();
        // 总数据长度
        int total = data.length;
        // 输出流
        ByteArrayOutputStream baos = new ByteArrayOutputStream();
        decodeByte(cipher, data, total, baos);
        return baos.toByteArray();
    }
    /**
     * 分段处理数据
     *
     * @param cipher  : Cipher对象
     * @param data    : 要处理的byte数组
     * @param total   : 总数据长度
     * @param baos    : 输出流
     * @throws Exception
     */
    private static void decodeByte(Cipher cipher, byte[] data, int total, ByteArrayOutputStream baos) throws Exception {
        // 偏移量
        int offset = 0;
        // 缓冲区
        byte[] buffer;
        // 如果数据没有处理完, 就一直继续
        while (total - offset > 0) {
            // 如果剩余的数据 >= 最大处理能力, 就按照最大处理能力来加密数据
            if (total - offset >= maxSize) {
                // 加密数据
                buffer = cipher.doFinal(data, offset, maxSize);
                // 偏移量向右侧偏移最大数据能力个
                offset += maxSize;
            } else {
                // 如果剩余的数据 < 最大处理能力, 就按照剩余的个数来加密数据
                buffer = cipher.doFinal(data, offset, total - offset);
                // 偏移量设置为总数据长度, 这样可以跳出循环
                offset = total;
            }
            // 向输出流写入数据
            baos.write(buffer);
        }
    }
}
